package edu.utd.text.game.domain.areas;

import java.util.ArrayList;

import edu.utd.text.game.domain.Descriptive;
import edu.utd.text.game.domain.GameObject;
import edu.utd.text.game.domain.exceptions.DuplicateGameObjectException;
import edu.utd.text.game.domain.exceptions.GameObjectNotFoundException;
import edu.utd.text.game.domain.item.GameItem;

/**
 * Room
 * This is a room in the game that a player can go into.
 * It might contain <code>GameObject</code>s.
 * All Rooms have exactly 8 exits that may or may
 * not point to a dead end (DeadEnd).  Exits are
 * cardinal directions (N, S, E, W, NE, NW, SE, SW).
 * @author troy
 *
 */

public class Room implements GameArea, Descriptive {
	
	//exits from the room
	private GameArea northExit = new DeadEnd();
	private GameArea southExit = new DeadEnd();
	private GameArea eastExit = new DeadEnd();
	private GameArea westExit = new DeadEnd();
	
	private GameArea northEastExit = new DeadEnd();
	private GameArea northWestExit = new DeadEnd();
	private GameArea southEastExit = new DeadEnd();
	private GameArea southWestExit = new DeadEnd();
	
	//array of game objects in this room
	private ArrayList<GameObject> objects;
	
	//a description of the room to be displayed
	private String description;
	
	//short name for this room
	private String roomName = "";
	
	  //////////////////
	 // Constructors //
	//////////////////
	
	public Room(ArrayList<GameObject> objects) {
		this("", objects);
	}
	
	public Room(String roomName) {
		this(roomName, new ArrayList<GameObject>());
	}
	
	public Room(String name, ArrayList<GameObject> objects) {
		this.roomName = name;
		this.objects = objects;
	}
	
	  ////////////////////////////////////
	 // manipulate objects in the room //
	////////////////////////////////////
	
	//add a GameObject to the Room, do not allow duplicates
	public void addGameObject(GameObject gameObjectToAdd) 
		throws DuplicateGameObjectException 
	{
		if(objects.contains(gameObjectToAdd)) {
			throw new DuplicateGameObjectException();
		}
		objects.add(gameObjectToAdd);
	}
	
	public boolean removeObjectFromRoom(GameObject gameObjectToRemove) {
		return objects.remove(gameObjectToRemove);
	}
	
	/**
	 * Returns the requested GameItem 
	 * WITHOUT removing it from the room.
	 * @param itemToRetrieve
	 * @return
	 */
	public GameItem retrieveGameItem(GameItem itemToRetrieve) 
		throws GameObjectNotFoundException 
	{
		ArrayList<GameObject> objects = getObjects();
		if(!objects.contains(itemToRetrieve))
				throw new GameObjectNotFoundException();
		
		//We should not get a ClassClastException here because
		//if the object we're looking for was found the in the
		//ArrayList, it should always be of type GameItem:
		return (GameItem)objects.get(getObjects().indexOf(itemToRetrieve));
	}
	
	/**
	 * Returns a GameItem WITHOUT removing it
	 * from the room.
	 * @param itemType
	 * @return
	 * @throws GameObjectNotFoundException
	 */
//	public GameItem retrieveGameItemOfType(Class itemType) 
//		throws GameObjectNotFoundException
//	{
//		ArrayList<GameObject> objects = getObjects();
//		for(GameObject anObject : objects) {
//			if(anObject.getClass().equals(itemType)) {
//				if(anObject instanceof GameItem) {
//					return (GameItem)anObject;
//				}
//			}
//		}
//		throw new GameObjectNotFoundException();
//	}
	
	//TEST ME!
	public GameItem retrieveGameItemByName(String itemName) 
		throws GameObjectNotFoundException
	{
		ArrayList<GameObject> objects = getObjects();
		for(GameObject anObject : objects) {
			if(anObject.getName().toLowerCase().equals(itemName.toLowerCase().trim())) {
				if(anObject instanceof GameItem) {
					return (GameItem)anObject;
				}
			}
		}
		throw new GameObjectNotFoundException();
	}
	
	public GameObject retrieveGameObjectByName(String objToRetrieveName) 
		throws GameObjectNotFoundException
	{
		ArrayList<GameObject> objects = getObjects();
		for(GameObject anObject : objects) {
			if(anObject.getName().toLowerCase().equals(objToRetrieveName.trim())) {
				return anObject;
			}
		}
		throw new GameObjectNotFoundException();
	}

	public boolean containsGameObjectOfType(Class objectType) {
		for(GameObject anObject : getObjects()) {
			if(anObject.getClass().equals(objectType))
				return true;
		}
		return false;
	}
	
	public String getStringListOfObjects() {
		String listOfGameObjects = "";
		for (GameObject gameObject : objects) {
			listOfGameObjects += gameObject.getName() + ", ";
		}
		return listOfGameObjects;
		
	}

	  /////////////
	 // Getters //
	/////////////

	public ArrayList<GameObject> getObjects() {
		return objects;
	}
	
	public GameArea getNorthExit() {
		return northExit;
	}

	public GameArea getSouthExit() {
		return southExit;
	}

	public GameArea getEastExit() {
		return eastExit;
	}

	public GameArea getWestExit() {
		return westExit;
	}

	public GameArea getNorthEastExit() {
		return northEastExit;
	}

	public GameArea getNorthWestExit() {
		return northWestExit;
	}

	public GameArea getSouthEastExit() {
		return southEastExit;
	}

	public GameArea getSouthWestExit() {
		return southWestExit;
	}
	
	public String getDescription() {
		if(!getObjects().isEmpty()) {
			return description + 
				"\nThe following objects are here:\n" + 
				getStringListOfObjects();
		}
		return description;
	}
	
	public String getRoomName() {
		return this.roomName;
	}
	
	  /////////////
	 // Setters //
	/////////////
	
	public void setNorthExit(GameArea northExit) {
		this.northExit = northExit;
	}

	public void setSouthExit(GameArea southExit) {
		this.southExit = southExit;
	}

	public void setEastExit(GameArea eastExit) {
		this.eastExit = eastExit;
	}

	public void setWestExit(GameArea westExit) {
		this.westExit = westExit;
	}

	public void setNorthEastExit(GameArea northEastExit) {
		this.northEastExit = northEastExit;
	}

	public void setNorthWestExit(GameArea northWestExit) {
		this.northWestExit = northWestExit;
	}

	public void setSouthEastExit(GameArea southEastExit) {
		this.southEastExit = southEastExit;
	}

	public void setSouthWestExit(GameArea southWestExit) {
		this.southWestExit = southWestExit;
	}

	public void setObjects(ArrayList<GameObject> objects) {
		this.objects = objects;
	}
	
	public void setDescription(String description) {
		this.description = description;
	}
	
	public void setRoomName(String roomName) {
		this.roomName = roomName;
	}
	
	  ///////////////////
	 // EQUALS METHOD //
	///////////////////
	
	//TODO: Test me!
	public boolean equals(Room other) {
		if(this.roomName.equals(other.getRoomName())) {
			return true;
		}
		return false;
	}
}
